﻿// 功能：
// 描述：
// 作者：温伟鹏
// 日期：2010/6/8 14:38:46

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Drawing;

namespace MeizuSDK.Drawing
{
    /// <summary>
    /// GDI绘制帮助类
    /// </summary>
    internal sealed class GDIHelper
    {
        #region GradientFill函数的三种倾斜填充模式
        /// <summary>
        /// 在该模式下，两个端点表示一个矩形。
        /// 该矩形被定义成左右边界具有固定颜色（由TRIVERTEX结构指定）。
        /// GDI从上至下插入颜色，并填充内部区域
        /// </summary>
        public const int GRADIENT_FILL_RECT_H = 0x00000000;
        /// <summary>
        /// 在该模式下，两个端点表示一个矩形。
        /// 该矩形定义其顶部和底部边界的颜色为固定值（通过TRIVERTEX结构指定），GDI从顶至底部边界插入颜色，并填充内部区域。
        /// </summary>
        public const int GRADIENT_FILL_RECT_V = 0x00000001;
        /// <summary>
        /// 在该模式下，TRIVERTEX结构数组以及描述单个三角形的数组索引序列被传给GDI。
        /// GDI在三角形顶点之间进行线性插值，并填充内部区域。
        /// 在24和32位／像素模式下，绘图是直接进行。在16、8、4和1位／像素模式中进行抖动处理。
        /// </summary>
        public const int GRADIENT_FILL_TRIANGLE = 0x00000010;
        #endregion

        /// <summary>
        /// 以渐变色填充矩形
        /// </summary>
        /// <param name="hdc">指向目标设备环境的句柄。GDI绘图图面</param>
        /// <param name="pVertex">指向TRIVERTEX结构数组的指针，该数组中的每项定义了三角形顶点</param>
        /// <param name="dwNumVertex">顶点数目</param>
        /// <param name="pMesh">三角形模式下的GRADIENT_TRIANGLE结构数组，或矩形模式下的GRADIENT_RECT结构数组</param>
        /// <param name="dwNumMesh">参数pMesh中的成员数目（这些成员是三角形或矩形）。</param>
        /// <param name="dwMode">指定倾斜填充模式。</param>
        /// <returns>如果函数执行成功，那么返回值为TRUE；如果函数执行失败，则返回值为FALSE。</returns>
        [DllImport("coredll.dll", SetLastError = true, EntryPoint = "GradientFill")]
        public extern static bool GradientFill(
            IntPtr hdc,
            TRIVERTEX[] pVertex,
            uint dwNumVertex,
            GRADIENT_RECT[] pMesh,
            uint dwNumMesh,
            uint dwMode);

        /// <summary>
        /// 根据句柄获取Window HDC
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <returns></returns>
        [DllImport("coredll", EntryPoint = "GetWindowDC", SetLastError = true)]
        private static extern IntPtr GetWindowDCCE(IntPtr hwnd);
        /// <summary>
        /// 根据窗口句柄获取窗口DC
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <returns></returns>
        public static IntPtr GetWindowDC(IntPtr hWnd)
        {
            IntPtr zero = IntPtr.Zero;

            zero = GetWindowDCCE(hWnd);

            if (zero == IntPtr.Zero)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "GetWindowDC函数执行失败");
            }

            return zero;
        }
        /// <summary>
        /// 根据句柄获取DC
        /// </summary>
        /// <param name="hwnd">句柄</param>
        /// <returns></returns>
        [DllImport("coredll", EntryPoint = "GetDC", SetLastError = true)]
        private static extern IntPtr GetDCCE(IntPtr hwnd);
        /// <summary>
        /// 根据句柄获取DC
        /// </summary>
        /// <param name="hWnd"></param>
        /// <returns></returns>
        public static IntPtr GetDC(IntPtr hWnd)
        {
            IntPtr zero = IntPtr.Zero;

            zero = GetDCCE(hWnd);

            if (zero == IntPtr.Zero)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "GetDC函数执行失败！");
            }

            return zero;
        }
        /// <summary>
        /// 释放设备上下文
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="hdc"></param>
        public static void ReleaseDC(IntPtr handle, IntPtr hdc)
        {
            SafeNativeMethods.CheckHandle(hdc);

            if (UnsafeNativeMethods.ReleaseDC(handle, hdc) == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "ReleaseDC函数执行失败");
            }
        }
        /// <summary>
        /// 设置指定设备上下文的背景颜色
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="crColor"></param>
        /// <returns></returns>
        [DllImport("coredll.dll", EntryPoint = "SetBkColor", SetLastError = true)]
        private static extern uint SetBkColorCE(IntPtr hdc, int crColor);
        /// <summary>
        /// 设置指定设备上下文的背景颜色
        /// </summary>
        /// <param name="hdc">设备上下文句柄</param>
        /// <param name="crColor">颜色COLORREF</param>
        /// <returns></returns>
        public static int SetBkColor(IntPtr hdc, int crColor)
        {
            SafeNativeMethods.CheckHandle(hdc);
            uint num = SetBkColorCE(hdc, crColor);
            if (num == uint.MaxValue)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "设置背景颜色失败.");
            }
            return Convert.ToInt32(num);
        }
        /// <summary>
        /// 设置指定设备上下文的背景模式
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="iBkMode"></param>
        /// <returns></returns>
        [DllImport("coredll.dll", EntryPoint = "SetBkMode", SetLastError = true)]
        private static extern int SetBkModeCE(IntPtr hdc, int iBkMode);
        /// <summary>
        /// 设置指定设备上下文的背景模式
        /// </summary>
        /// <param name="hdc">设备上下文句柄</param>
        /// <param name="iBkMode">背景模式</param>
        /// <returns></returns>
        public static BackgroundMode SetBkMode(IntPtr hdc, BackgroundMode iBkMode)
        {
            SafeNativeMethods.CheckHandle(hdc);

            int num = SetBkModeCE(hdc, (int)iBkMode);
            if (num == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "BackgroundMode函数执行失败。");
            }
            return (BackgroundMode)num;
        }

        /// <summary>
        /// 该函数用来显示透明或半透明像素的位图
        /// </summary>
        /// <param name="hdcDest">指向目标设备环境的句柄。</param>
        /// <param name="xDest">指定目标矩形区域左上角的X轴坐标，按逻辑单位。</param>
        /// <param name="yDest">指定目标矩形区域左上角的Y轴坐标，按逻辑单位。</param>
        /// <param name="widthDest">指定目标矩形区域的宽度，按逻辑单位。</param>
        /// <param name="heightDest">指向目标矩形区域高度的句柄，按逻辑单位。</param>
        /// <param name="hdcSrc">指向源设备环境的句柄。</param>
        /// <param name="xSrc">指定源矩形区域左上角的X轴坐标，按逻辑单位。</param>
        /// <param name="ySrc">指定源矩形区域左上角的Y轴坐标，按逻辑单位。</param>
        /// <param name="cxSrc">指定源矩形区域的宽度，按逻辑单位。</param>
        /// <param name="cySrc">指定源矩形区域的高度，按逻辑单位。</param>
        /// <param name="blendFunction">
        /// 指定用于源位图和目标位图使用的alpha混合功能，用于整个源位图的全局alpha值和格式信息。
        /// 源和目标混合功能当前只限为AC_SRC_OVER。
        /// </param>
        /// <returns>如果函数执行成功，那么返回值为TRUE；如果函数执行失败，那么返回值为FALSE。</returns>
        [DllImport("coredll.dll")]
        public extern static Int32 AlphaBlend(
            IntPtr hdcDest, Int32 xDest, Int32 yDest, Int32 widthDest, Int32 heightDest,
            IntPtr hdcSrc, Int32 xSrc, Int32 ySrc, Int32 widthSrc, Int32 heightSrc,
            BlendFunction blendFunction);

        /// <summary>
        /// 该函数对指定的源设备环境区域中的像素进行位块（bit_block）转换，以传送到目标设备环境。
        /// </summary>
        /// <param name="hdcDest">指向目标设备环境的句柄。</param>
        /// <param name="nXDest">指定目标矩形区域左上角的X轴逻辑坐标。</param>
        /// <param name="nYDest">指定目标矩形区域左上角的Y轴逻辑坐标。</param>
        /// <param name="nWidth">指定源和目标矩形区域的逻辑宽度。</param>
        /// <param name="nHeight">指定源和目标矩形区域的逻辑高度。</param>
        /// <param name="hdcSrc">指向源设备环境的句柄。</param>
        /// <param name="nXSrc">指定源矩形区域左上角的X轴逻辑坐标。</param>
        /// <param name="nYSrc">指定源矩形区域左上角的Y轴逻辑坐标。</param>
        /// <param name="dwRop">
        /// 指定光栅操作代码。
        /// 这些代码将定义源矩形区域的颜色数据，如何与目标矩形区域的颜色数据组合以完成最后的颜色。
        /// </param>
        /// <returns>如果函数成功，那么返回值非零；如果函数失败，则返回值为零。</returns>
        [DllImport("coredll.dll")]
        public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth,
           int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

        /// <summary>
        /// 绘制透明图像
        /// </summary>
        /// <param name="gx">绘图图面</param>
        /// <param name="image">要绘制的图片</param>
        /// <param name="transp">透明度</param>
        /// <param name="x">目标X坐标</param>
        /// <param name="y">目标Y坐标</param>
        public static void DrawAlpha(Graphics gx, Bitmap image, byte transp, int x, int y)
        {
            using (Graphics gxSrc = Graphics.FromImage(image))
            {
                IntPtr hdcDst = gx.GetHdc();
                IntPtr hdcSrc = gxSrc.GetHdc();
                BlendFunction blendFunction = new BlendFunction();
                blendFunction.BlendOp = (byte)BlendOperation.AC_SRC_OVER;   // Only supported blend operation
                blendFunction.BlendFlags = (byte)BlendFlags.Zero;           // Documentation says put 0 here
                blendFunction.SourceConstantAlpha = transp;                  // Constant alpha factor
                blendFunction.AlphaFormat = (byte)0;                        // Don't look for per pixel alpha
                AlphaBlend(hdcDst, x, y, image.Width, image.Height, hdcSrc, 0, 0, image.Width, image.Height, blendFunction);
                gx.ReleaseHdc(hdcDst);    // Required cleanup to GetHdc()
                gxSrc.ReleaseHdc(hdcSrc);       // Required cleanup to GetHdc()
            }
        }
    }
}
